#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ucontext.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sched.h>
#include <sys/mman.h>
#include <x86intrin.h>
#include <linux/videodev2.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define CYCLE 10000

#define TARGET_OFFSET	12
#define TARGET_SIZE	(1 << TARGET_OFFSET)
#define BITS_READ	2
#define VARIANTS_READ	(1 << BITS_READ)

// static char target_array[VARIANTS_READ * TARGET_SIZE];
static char *target_array = NULL;

static char gr_array[1024*8];


static inline int get_access_time(volatile char *addr)
{
	unsigned long long time1, time2;
	unsigned junk;
	time1 = __rdtscp(&junk);
	(void)*addr;
	time2 = __rdtscp(&junk);
	return time2 - time1;
}

void load_target(int page)
{
    char x = target_array[TARGET_SIZE*page];
}

void clflush_target(void)
{
	int i;
	for (i = 0; i < VARIANTS_READ; i++)
		_mm_clflush(&target_array[i * TARGET_SIZE]);

}

int main() 
{
    int i;
	int average_time;
	unsigned long total = 0;
	int fd;
	if (target_array == NULL)
	{
		fd = open("/dev/mem", O_RDONLY, 0);
		if (fd < 0){
			printf("open /dev/mem failuer\n");
			exit(-1);
		}
		target_array = (char *)mmap(0, 4*4096, PROT_READ, MAP_SHARED, fd, 0xf0000);
		if (!target_array){
			printf("mmap error\n");
			exit(-1);
		}
	}
	printf("flush --------------------------\n");
    clflush_target();
	
	char ch = 20;
	int j = 0;
	for (i=0; i<256; i++) 
	{
		total = 0;
		for (j = 0; j<CYCLE; j++) {
			clflush_target();
			total += get_access_time(&target_array[2*4096+i-ch]);
		}
		average_time = total / CYCLE;
		printf("%d %d %d \n", i, i-ch, average_time);
	}
	printf("\n");
	if (fd > 0){
		close(fd);
	}
	return 0;
}
